//
// Created by Gorun on 2022/5/2.
//

#ifndef LOXPP_ERROR_H
#define LOXPP_ERROR_H

#include <iostream>
#include <string_view>
#include <cstring>
#include <cstdio>

#include "Token.h"
#include "RuntimeError.h"

using namespace std;

extern string getLine(int line);

inline bool hadError = false;
inline bool hadRuntimeError = false;

inline void report(bool isDynamic, int line, int column, string_view where, string_view message) {
    if (isDynamic)
        cout<<"Dynamic ";
    else
        cout<<"Static ";

    if (where.length()!=0)
        cout<<"Error: "<<where<<" | "<<message<<endl;
    else
        cout<<"Error: "<<message<<endl;

    char buffer[128];
    sprintf(buffer, "[%d, %d] | ", line, column);
    int prefixLength = static_cast<int>(strlen(buffer))-1;

    printf("[%d, %d] | ", line, column); cout<<getLine(line)<<endl;

    for (int i=1; i<=prefixLength+column; i++)
        putchar(' ');
    printf("^-- Here\n\n");

    hadError=true;
}

inline void error(const Token& token, string_view message) { //Parser error and Resolver error(static)
    if (token.type==END) {
        report(false, token.line, token.column, "at end", message);
    } else {
        report(false, token.line, token.column, "at '"+token.lexeme+"'", message);
    }
}

inline void error(int line, int column, string_view message) { //Scanner error (static)
    report(false, line, column, "", message);
}

inline void runtimeError(const RuntimeError& error) { //Interpreter error (dynamic)
    report(true, error.token.line, error.token.column, "", error.what());
    hadRuntimeError = true;
}

#endif //LOXPP_ERROR_H
